#
# LsL::User.pm
#
# Copyright (C) 2004 Albacore Technology, LLC All Rights Reserved
#
#

# NOTE: The calls to set_user/get_user must be done on the same server

package LsL::User;

use strict;
use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );
use Exporter;

@EXPORT_OK = qw();
@ISA       = qw(Exporter);
@EXPORT    = qw();
$VERSION   = 0.1;

my $_user_cache = undef;
my $_role_cache = undef;

sub update_whats_new {
  my ($userid) = @_;

  HTML::Shark::D_User::update_whats_new({'userid' => $userid});
}

sub online_sessions {
  my ($userinfo,$max_session_age,$ccode) = @_;

  $max_session_age = (5 * 60) unless( $max_session_age );

  my $age = $max_session_age;

  $ccode = $userinfo->{ 'ccode' } unless( $ccode );

  my $sessions;

  if ($ccode eq 'XX') {
    $sessions = HTML::Shark::D_User::get_online_sessions({'age' => $age});
  } else {
    $sessions = HTML::Shark::D_User::get_online_sessions({'age'   => $age,
                                                   'ccode' => $ccode});
  }

  return $sessions;
}

sub install_user_cookies_by_domain {
  my ($userinfo, $domain) = @_;

  my $cookies = HTML::Shark::D_Auth::get_cookies_by_domain(
    {session_key => $userinfo->{'session_key'},
     domain      => $domain});

  foreach my $cookie (@{$cookies}) {
    $userinfo->{'cookie_jar'}{$domain}{$cookie->{'name'}} = $cookie->{'value'};
  }
}

sub save_user_cookies_by_domain {
  my ($userinfo, $domain, $ckeys, $orig, $new, $submit) = @_;

  # loop through cookies
  foreach my $cname (@{$ckeys}) {
    # check if cookie now empty
    if (exists $orig->{$cname} && $submit && (!exists $new->{$cname} || $new->{$cname} eq '')) {
      # remove cookie
      HTML::Shark::D_Auth::remove_cookie(
        {session_key => $userinfo->{'session_key'},
         domain      => $domain,
         name        => $cname,
        });
    } elsif ($orig->{$cname} ne $new->{$cname}) {
      # value changed, write it out
      HTML::Shark::D_Auth::set_cookie_small(
        {session_key => $userinfo->{'session_key'},
         domain      => $domain,
         name        => $cname,
         value       => $submit ? $new->{$cname} : $orig->{$cname},
        });
    }
  }
}

sub set_user {
  my ($session_key, $userid, $entity_id, $cis_entity_id, $cis_entity_type) = @_;


  return undef unless ( $session_key && $userid );

  $_user_cache ||=
    Cache::FileCache->new( { namespace  => 'Shark-Users',
                             cache_root => '/tmp/fc_pusers',
                             default_expires_in  => 60 * 60 * 24, # 1 day
                             auto_purge_interval => 60 * 60 * 24, # 1 day
                             auto_purge_on_set => 1 } );

  # build user hash, will cache in the future
  my $userinfo     = HTML::Shark::D_User::get_user_info      ({'userid' => $userid});
  my $roles        = HTML::Shark::D_User::get_user_roles     ({'userid' => $userid});
  my $client_roles = HTML::Shark::D_CCode::ccode_role_select ({'ccode'  => $userinfo->{'ccode'}});

  foreach my $role (@{$roles}) {
    $userinfo->{'roles'}{$role->{'role_id'}} = 1;
  }

  foreach my $role (@{$client_roles}) {
    $userinfo->{'client_roles'}{$role} = 1;
  }

  $userinfo->{'entity_id'}       = $entity_id;
  $userinfo->{'cis_entity_id'}   = $cis_entity_id;
  $userinfo->{'cis_entity_type'} = $cis_entity_type;
  $userinfo->{'session_key'}     = $session_key;

  # set fullname
  $userinfo->{'fullname'} =
     Data::Shark::Util::mc($userinfo->{'fname'} . ' ' . $userinfo->{'lname'});
  $userinfo->{'name'} = $userinfo->{'fullname'};

  $_user_cache->set( $session_key, $userinfo );

  return 1;
}

sub get_user {
  my ($session_key) = @_;

  return undef unless $session_key; # no session defined yet

  $_user_cache ||=
    Cache::FileCache->new( { namespace  => 'Shark-Users',
                             cache_root => '/tmp/fc_pusers',
                             default_expires_in  => 60 * 60 * 24, # 1 day
                             auto_purge_interval => 60 * 60 * 24, # 1 day
                             auto_purge_on_set => 1 } );

  return $_user_cache->get($session_key);
}

sub set_entity_id {
  my ($userinfo, $entity_id) = @_;

  $_user_cache ||=
    Cache::FileCache->new( { namespace  => 'Shark-Users',
                             cache_root => '/tmp/fc_pusers',
                             default_expires_in  => 60 * 60 * 24, # 1 day
                             auto_purge_interval => 60 * 60 * 24, # 1 day
                             auto_purge_on_set => 1 } );

  $entity_id = undef unless ($entity_id);

  HTML::Shark::D_Auth::session_entity({'entity_id' => $entity_id, 'session_id' => $userinfo->{'session_key'}});

  $userinfo->{'entity_id'} = $entity_id;

  $_user_cache->set( $userinfo-{'session_key'}, $userinfo );
}

sub set_cis_entity_id {
  my ($userinfo, $entity_id, $type) = @_;

  $_user_cache ||=
    Cache::FileCache->new( { namespace  => 'Shark-Users',
                             cache_root => '/tmp/fc_pusers',
                             default_expires_in  => 60 * 60 * 24, # 1 day
                             auto_purge_interval => 60 * 60 * 24, # 1 day
                             auto_purge_on_set => 1 } );

  $entity_id = undef unless ($entity_id);

  HTML::Shark::D_Auth::session_cis_entity({entity_type => $type, entity_id => $entity_id, session_id => $userinfo->{'session_key'}});

  $userinfo->{'cis_entity_id'}   = $entity_id;
  $userinfo->{'cis_entity_type'} = $type;

  $_user_cache->set( $userinfo-{'session_key'}, $userinfo );
}

sub check_role {

  my ($userinfo, $role, $oper) = @_;

  $oper = 'or' unless $oper eq 'and';

  my $ok = ($oper eq 'and'?1:0);

  if (ref $role eq 'ARRAY') {
    foreach (@$role) {
      my $result = (exists( $userinfo->{'roles'}{$_} ) ? 1 : 0);
      $ok = ($oper eq 'and') ? ($ok & $result) : ($ok | $result);
    }
  } else {
    $ok = exists $userinfo->{'roles'}{$role};
  }

  return $ok;
}

sub check_ccode_role {

  my ($userinfo, $role, $oper) = @_;

  $oper = 'or' unless $oper eq 'and';

  my $ok = ($oper eq 'and'?1:0);

  if (ref $role eq 'ARRAY') {
    foreach (@$role) {
      my $result = (exists( $userinfo->{'client_roles'}{$_} ) ? 1 : 0);
      $ok = ($oper eq 'and') ? ($ok & $result) : ($ok | $result);
    }
  } else {
    $ok = exists $userinfo->{'client_roles'}{$role};
  }

  return $ok;
}

sub roles {
  my ($userinfo) = @_;

  my $roles = [];

  push @{$roles}, $_ foreach (keys %{$userinfo->{'roles'}});

  return $roles;
}

sub get_user_info {
  my ($userid, $do_roles) = @_;

  $userid =~ s/[^0-9]//g;

  return {} unless $userid;

  # build user hash, will cache in the future
  my $userinfo = HTML::Shark::D_User::get_user_info({'userid' => $userid});

  if ($do_roles) {
    my $roles        = HTML::Shark::D_User::get_user_roles({'userid' => $userid});
    my $client_roles = HTML::Shark::D_CCode::ccode_role_select({'ccode' => $userinfo->{'ccode'}});

    foreach my $role (@{$roles}) {
      $userinfo->{'roles'}{$role->{'role_id'}} = 1;
    }

    foreach my $role (@{$client_roles}) {
      $userinfo->{'client_roles'}{$role} = 1;
    }
  }

  # set fullname
  $userinfo->{'fullname'} =
    Data::Shark::Util::mc($userinfo->{'fname'} . ' ' . $userinfo->{'lname'});

  $userinfo->{'name'} = $userinfo->{'fullname'};

  return $userinfo;
}

sub get_lcodes {
  my ($all) = @_;

  my $res = (defined $all) ?
    HTML::Shark::D_LCode::lcode_all() : HTML::Shark::D_LCode::lcode_active();

  return wantarray ? ([], {}) : {}
    unless( $res && @{$res} );

  if (wantarray) {
    my @lcodes = ();
    my %lcode_labels = ();
    for (@{$res}) {
      next if( exists $lcode_labels{ $_->{'lcode'} } );
      push @lcodes, $_->{'lcode'};
      $lcode_labels{ $_->{'lcode'} } = $_->{'name'} ? "$_->{'name'}" : $_->{'lcode'};
      #$lcode_labels{ $_->{'lcode'} } = $_->{'name'} ? "$_->{'lcode'}: $_->{'name'}" : $_->{'lcode'};
    }
    return (\@lcodes, \%lcode_labels);
  }
  return $res;
}

sub get_ccodes {
  my ($all) = @_;

  my $res = (defined $all) ?
    HTML::Shark::D_CCode::ccode_all() : HTML::Shark::D_CCode::ccode_active();

  return wantarray ? ([], {}) : {}
    unless( $res && @{$res} );

  if (wantarray) {
    my @ccodes = ();
    my %ccode_labels = ();
    for (@{$res}) {
      next if( exists $ccode_labels{ $_->{'ccode'} } );
      push @ccodes, $_->{'ccode'};
      $ccode_labels{ $_->{'ccode'} } = $_->{'name'} ? "$_->{'name'}" : $_->{'ccode'};
      #$ccode_labels{ $_->{'ccode'} } = $_->{'name'} ? "$_->{'ccode'}: $_->{'name'}" : $_->{'ccode'};
    }
    return (\@ccodes, \%ccode_labels);
  }
  return $res;
}

sub get_login_ccodes {

  my $res = HTML::Shark::D_CCode::ccode_login();

  return wantarray ? ([], {}) : {}
    unless( $res && @{$res} );

  if (wantarray) {
    my @ccodes = ();
    my %ccode_labels = ();
    for (@{$res}) {
      next if( exists $ccode_labels{ $_->{'ccode'} } );
      push @ccodes, $_->{'ccode'};
      $ccode_labels{ $_->{'ccode'} } = "$_->{'ccode'}: $_->{'name'}";
    }
    return (\@ccodes, \%ccode_labels);
  }
  return $res;
}

sub get_roles {

  # build role cache
  unless ($_role_cache) {
    my $res = HTML::Shark::D_User::get_roles();
    $_role_cache = {};

    $_role_cache->{$_->{'role'}} = $_ foreach (@{$res});
  }

  return wantarray ? ([], {}) : {}
    unless( $_role_cache && scalar keys %{$_role_cache} );

  if( wantarray ) {
    my @roles = ();
    my %role_labels = ();
    for my $role (sort {$_role_cache->{$a}{'name'}
                        cmp $_role_cache->{$b}{'name'}} keys %{$_role_cache}) {
      next if( exists $role_labels{ $_role_cache->{$role}{'role'} } );
      push @roles, $_role_cache->{$role}{'role'};
      $role_labels{$_role_cache->{$role}{'role'}} = $_role_cache->{$role}{'name'};
    }
    return (\@roles, \%role_labels);
  }
  return $_role_cache;
}

sub role_restricted {
  my ($role) = @_;

  # build role cache
  unless ($_role_cache) {
    my $res = HTML::Shark::D_User::get_roles();
    $_role_cache = {};

    $_role_cache->{$_->{'role'}} = $_ foreach (@{$res});
  }

  return 0 unless exists $_role_cache->{$role};

  return ($_role_cache->{$role}{'restricted'}?1:0);
}

sub revoke_user_roles {
  my ($userids, $role_ids) = @_;

  $userids  = LsL::Util::make_arrayref( $userids );
  $role_ids = LsL::Util::make_arrayref( $role_ids );

  return if $userids  && !(scalar @{$userids});
  return if $role_ids && !(scalar @{$role_ids});

  my $userid_list  = join(',', map { '?' } @${userids});
  my $role_id_list = join(',', map { '?' } @${role_ids});

  my $sql = qq{delete from user_role where userid in ($userid_list) and role_id in ($role_id_list)};

  my $dbi = LsL::DB::sdbi();
  my $sth;

  $sth = $dbi->db_prep($sql);
  $dbi->db_exec($sth, @{$userids}, @${role_ids});
  $dbi->db_done($sth);
}

sub grant_user_roles {
  my ($userids, $role_ids) = @_;

  $userids  = LsL::Util::make_arrayref( $userids );
  $role_ids = LsL::Util::make_arrayref( $role_ids );

  return if $userids  && !(scalar @{$userids});
  return if $role_ids && !(scalar @{$role_ids});

  revoke_user_roles( $userids, $role_ids );

  for my $userid (@{$userids}) {
    next unless( $userid );
    for my $role_id (@{$role_ids}) {
      next unless( $role_id );
      HTML::Shark::D_Profile::user_role_insert({userid => $userid, role => $role_id});
    }
  }
}

sub disable_users {
  my ($userids) = @_;

  for my $userid (@{$userids}) {
    next unless( $userid );

    HTML::Shark::D_User::set_user_disabled({'userid' => $userid});

  }
}

sub get_multiple_user_roles {
  my ($userids) = @_;

  $userids = LsL::Util::make_arrayref( $userids );
  my $userid_list = join(',', map { '?' } @${userids});

  my $sql = qq{
    select userid,
           role_id
      from user_role
     where userid in ($userid_list)
     order by userid, role_id
  };

  my $dbi = LsL::DB::sdbi();
  my $sth;

  $sth = $dbi->db_prep($sql);
  $dbi->db_exec($sth, @{$userids});

  my $users = ();
  while(my @d = $dbi->db_fetch($sth)) {
    $users->{$d[0]} = []
      unless( exists $users->{$d[0]} );
    push @{$users->{$d[0]}}, $d[1];
  }

  $dbi->db_done($sth);

  return $users;
}



1;
